package org.example.component;

import lombok.Setter;
import org.example.service.UserService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 帮我们创建代理对象一个工具处理类
 *
 * 需求：为目标（被）对象 创建代理对象并且实现功能增强（处理事务）
 */
public class JDKDynamicProxyHandler {

    //被代理的对象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //要增强的功能(事务管理器方法)
    private TransactionManagerHandler txManager;

    public void setTxManager(TransactionManagerHandler txManager) {
        this.txManager = txManager;
    }

    /**
     * 返回被代理对象的方法
     * @return
     */
    public UserService getProxy() {

        /**
         * Proxy.newProxyInstance 创建代理对
         * 方法参数说明
         * ClassLoader loader,
         *   类加载器(用于加载类)
         *   两种方式获取
         *
         * Class<?>[] interfaces,
         *  被代理对象的接口
         * InvocationHandler h
         *  处理器：真正要代理的功能编写代码的地方
         */
        //方式一：使用当前线程获取类加载器
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        //方式二：使用类的字节码对象获取
//        ClassLoader classLoader = target.getClass().getClassLoader();

        //被代理对象的接口
        Class<?>[] interfaces = target.getClass().getInterfaces();

        Object proxy = Proxy.newProxyInstance(classLoader, interfaces, new java.lang.reflect.InvocationHandler() {
            /**
             *
             * @param proxy 代理对象
             *
             * @param method 被代理对象的方法
             *
             * @param args 被代理方法的参数
             *
             * @return 被代理对象方法执行以后返回的结果
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                Object result = null;
                try {
                    txManager.begin();
                    //使用反射执行被代理对象的方法
                     result = method.invoke(target, args);

                    txManager.commit();
                } catch (Exception e) {
                    txManager.rollback();
                    throw new RuntimeException(e);
                } finally {
                    txManager.close();
                }
                return result;
            }
        });

        return (UserService) proxy;


    }


}


